#include "HightlightLine.h"
#include <osg/BufferObject>
#include <osg/PrimitiveSet>
#include <QString>
#include <osgEarth/ECEF>
#include <qdebug.h>

HightlightLineScene::HightlightLineScene()
{
}


HightlightLineScene::~HightlightLineScene()
{
}

void HightlightLineScene::addLine(HLine& hl)
{
	HLineImp imp;
	imp.line = hl;
	imp.context = &this->context;
	this->context.lines.push_back(imp);
}
#include <QFile>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonArray>
#include <QJsonObject>
bool HightlightLineScene::loadData()
{
#ifdef _DEBUG
	HLine line;
	line.lon0 = 100;
	line.lat0 = 0;
	line.lon1 = 150;
	line.lat1 = 0;

	this->addLine(line);
	return true;
#endif // _DEBUG

	QString filepath = "../user_data/cyber/data/t2.json";

	QFile file;
	file.setFileName(filepath);
	file.open(QIODevice::ReadOnly | QIODevice::Text);
	QString jsonstr = file.readAll();
	file.close();
	QJsonParseError jsonError;
	QJsonDocument document = QJsonDocument::fromJson(jsonstr.toUtf8(), &jsonError);

	if (document.isNull() || (jsonError.error != QJsonParseError::NoError)){
		return false;
	}
	if (!document.isArray()) return false;

	QJsonArray arr = document.array();
	for (int i = 0; i < arr.size(); i++)
	{
		QJsonObject v = arr.at(i).toObject();
		double lon1 = v.value("lon1").toDouble();
		double lat1 = v.value("lat1").toDouble();
		double lon2 = v.value("lon2").toDouble();
		double lat2 = v.value("lat2").toDouble();
		int ID = v.value("ID").toInt();
		int type = v.value("type").toInt();
		QString srccity = v.value("src_city").toString();
		QString destcity = v.value("dest_city").toString();
		HLine line;
		line.lon0 = lon1;
		line.lat0 = lat1;
		line.lon1 = lon2;
		line.lat1 = lat2;
		line.id = ID;
		line.type = type;
		line.webtype = line.getWebType();
		line.src_city = srccity;
		line.dest_city = destcity;

		this->addLine(line);
	}
	return true;
}

#define MAX_HEIGHT 2000000000
#define MIN_HEIGHT 200000
void HightlightLineScene::_buildLines()
{
	HLineImpList::iterator iter = context.lines.begin();
	while (iter != context.lines.end())
	{
		HLineImp* lineImp = &(*iter);
		lineImp->points = new osg::Vec3Array();
		HLine& line = lineImp->line;
		osg::Vec3 v0(line.lon0, line.lat0,0);
		osg::Vec3 v1(line.lon1, line.lat1,0);

		if (line.lon0 - line.lon1 > 180){
			v1.x() = line.lon0 + 360;
		}
		else if (line.lon0 - line.lon1 < -180){
			v1.x() = line.lon0 - 360;
		}
		
		osg::Vec3 p0 = this->llhToXYZ(v0);
		osg::Vec3 p1 = this->llhToXYZ(v1);
		osg::Vec3 p;
		
		{
			osg::Vec3 p2 = p1 - p0;
			osg::Vec3 p3 = p1 ^ p0;
			p3.normalize();
			p3 = p2 ^ p3;
			p3.normalize();
			p = (p0 + p1)*0.5 + p3 * (p1 - p0).length() *  0.25;
		}
		double r = (p0 - p).length();
		osg::Vec3 n0 = p0 - p;
		osg::Vec3 n1 = p1 - p;
		n0.normalize();
		n1.normalize();

		double angle = acos(n0 *n1);
		osg::Vec3d axis = n0 ^ n1;

		int segs = (v1 - v0).length() * 5;
		for (int i = 0; i < segs;i += 1)
		{
			float n = (float)i / (segs-1);
			osg::Quat q(angle * n, axis);
			osg::Vec3 v = p + q * n0 * r;
			lineImp->points->push_back(v);
		}

		iter++;
	}
}

//class HighlightCallback : public osg::NodeCallback
//{
//public:
//	virtual void operator()(osg::Node* node, osg::NodeVisitor* nv){
//		osg::Geode* geode = node->asGeode();
//		if (!geode) return;
//
//		int count = geode->getNumDrawables();
//		for (int i = 0; i < count; i++)
//		{
//			osg::Drawable* geom = geode->getDrawable(i);
//			geom->setDrawCallback()
//		}
//	}
//};

osg::Node* HightlightLineScene::createNode()
{
	_buildLines();
	osg::Geode* geode = new osg::Geode();
	HLineImpList::iterator iter = context.lines.begin();
	while (iter != context.lines.end())
	{
		HLineImp* lineImp = &(*iter);
		HLine& line = lineImp->line;

		osg::Vec3Array* vertices = lineImp->points.get();
		//osg::ref_ptr<osg::Geometry> lineGeom = new osg::Geometry;
		HightlightLineGeometry* lineGeom = new HightlightLineGeometry();
		lineGeom->setHLine(lineImp);
		lineGeom->buildCircles(getSceneContext()->getEllipsoidModel());
		lineGeom->setVertexArray(vertices);
		lineGeom->setUpdateCallback(new HightlightLineGeometry::HightlightLineGeometryCallback());

		osg::Vec4Array* colors = new osg::Vec4Array;
		colors->push_back(lineGeom->_color);
		lineGeom->setColorArray(colors, osg::Array::BIND_OVERALL);
		lineGeom->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::LINE_STRIP, 0, vertices->size()));

		lineGeom->setUseVertexBufferObjects(true);
		lineGeom->setUseDisplayList(false);

		geode->addDrawable(lineGeom);

		iter++;
	}
	return geode;
}

void HightlightLineScene::setType(int i )
{
	if (i == context._checktype) {
		context._checktype = -1;
	}
	else {
		context._checktype = i;
	}
}

void HightlightLineScene::setCity(QString s, int i)
{
	context._city = s;
	qDebug() << s;
}


void HightlightLineGeometry::HightlightLineGeometryCallback::update(osg::NodeVisitor* nv, osg::Drawable* o)
{

	HightlightLineGeometry* geom = dynamic_cast<HightlightLineGeometry*>(o);
	if (!geom) return;

	osg::DrawArrays* da = dynamic_cast<osg::DrawArrays*>(geom->getPrimitiveSet(0));
	if (!da) return;

	double reftime = nv->getFrameStamp()->getReferenceTime();
	if (reftime < geom->_simuTime){
		geom->_framesUnVisible++;
		return;
	}


	geom->_render = true;
	geom->_simuTime = reftime;
	geom->_framesUnVisible = 0;

	if (geom->_segments <= geom->_index){
		geom->_index = 0;
		geom->_simuTime += (rand() % 5)+1;
		geom->_render = false;
		return;
	}
	int count = geom->_count;
	if (geom->_segments - geom->_index < count){
		count = geom->_segments - geom->_index;
	}
	da->setFirst(geom->_index);
	da->setCount(count);

	geom->_index += geom->_step;

	//da->dirty();
}

void HightlightLineGeometry::setSegments(int segs)
{
	_segments = segs;
	_count = segs / 3;
	_step = segs / 200;
	_index = rand() % segs;

	int type = rand() % 3;
	if (type == 0){
		this->_color = osg::Vec4(153 / 255.0f, 217 / 255.0f, 234 / 255.0f, 1.0f);
	}
	else if (type == 1){
		this->_color = osg::Vec4(255 / 255.0f, 127 / 255.0f, 39 / 255.0f, 1.0f);
	}
	else if (type == 2){
		this->_color = osg::Vec4(255 / 255.0f, 255 / 255.0f, 128 / 255.0f, 1.0f);
	}

}

void HightlightLineGeometry::setHLine(HLineImp* line)
{
	int segs = line->points->size();
	_line = line;
	_segments = segs;
	_count = segs / 3;
	_step = segs / 75;
	_index = rand() % segs;

	int type = line->line.webtype;
	if (type == 0){
		this->_color = osg::Vec4(228 / 255.0f, 28 / 255.0f, 28 / 255.0f, 1.0f);
	}
	else if (type == 1){
		this->_color = osg::Vec4(255 / 255.0f, 255 / 255.0f, 0 / 255.0f, 1.0f);
	}
	else if (type == 2){
		this->_color = osg::Vec4(128 / 255.0f, 255 / 255.0f, 0 / 255.0f, 1.0f);
	}
	else if (type == 3) {
		this->_color = osg::Vec4(255 / 255.0f, 128 / 255.0f, 255 / 255.0f, 1.0f);
	}
	else if (type == 4) {
		this->_color = osg::Vec4(128 / 255.0f, 255 / 255.0f, 255 / 255.0f, 1.0f);
	}
}

void HightlightLineGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
{

	if (!this->_line) return;
	auto c = this->_line->context;
	int resss = c->checkRule(this->_line);
	if (resss == 0) return;

	//geom->_visible = true;

	//if (!_visible) return;
	if (_render){
		osg::Geometry::drawImplementation(renderInfo);
	}
	else if(_framesUnVisible <= 50){
		int i1 = _framesUnVisible / 10;
		for (int i = 0; i < i1; i++){
			_circles.at(i)->drawImplementation(renderInfo);
		}
	}
}

void HightlightLineGeometry::buildCircles(const osg::EllipsoidModel* em)
{
	if (!_line){
		return;
	}

	double lon = _line->line.lon1;
	double lat = _line->line.lat1;

	lon = osg::DegreesToRadians(lon);
	lat = osg::DegreesToRadians(lat);

	osg::Vec3d xyz;
	em->convertLatLongHeightToXYZ(lat, lon, 10000, xyz.x(), xyz.y(), xyz.z());
	osg::Matrix mat;
	em->computeLocalToWorldTransformFromXYZ(xyz.x(), xyz.y(), xyz.z(), mat);
	//mat = osg::Matrix::inverse(mat);
	double arr[5] = { 15 * 1000, 30 * 1000, 45 * 1000, 60 * 1000, 75 * 1000 };
	for (int i = 0; i < 5;i++)
	{
		osg::Vec3Array* vertices = new osg::Vec3Array();
		for (int r = 0; r < 18;r++)
		{
			double ra = r / 17.0 * osg::PI * 2;
			osg::Quat q(ra, osg::Vec3(0,0,1));
			osg::Vec3d v = q * osg::Vec3(arr[i], 0, 0);
			v.z() = arr[i];
			v =  v * mat;
			vertices->push_back(v);
		}
		osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
		geom->setVertexArray(vertices);
		osg::Vec4Array* colors = new osg::Vec4Array;
		colors->push_back(this->_color);
		geom->setColorArray(colors, osg::Array::BIND_OVERALL);
		geom->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::LINE_STRIP, 0, vertices->size()));

		this->_circles.push_back(geom);
	}
}

int HightlightLineSceneContext::checkRule(HLineImp * hi)
{
	HLine* line = &(hi->line);
	int res = 1;
	if (this->_checktype != -1) {
		if (line->webtype != this->_checktype) {
			res = 0;
		}
	}
	
	if (this->_city.length() > 0) {
		if (line->dest_city != this->_city) {
			res = 0;
		}
	}
	return res;
}

int HLine::getWebType()
{
	if (this->type >= 1 && this->type <= 33) {
		return 0;
	}
	if (this->type >= 34 && this->type <= 48) {
		return 1;
	}
	if (this->type >= 49 && this->type <= 59) {
		return 2;
	}
	if (this->type >= 60 && this->type <= 80) {
		return 3;
	}
	if (this->type >= 81 && this->type <= 100) {
		return 4;
	}
	
	return 0;

}
